package top.lingkang.mm.override;

import cn.hutool.core.util.StrUtil;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.reflection.invoker.Invoker;
import top.lingkang.mm.error.MagicException;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;

/**
 * 增加驼峰转化 get 、set
 *
 * @author lingkang
 * Created by 2024/3/3
 */
public class MagicReflector extends Reflector {
    private static Field getMethodsField, getTypesField, setMethodsField, setTypesField, mapField;

    static {
        try {
            getMethodsField = Reflector.class.getDeclaredField("getMethods");
            getMethodsField.setAccessible(true);

            getTypesField = Reflector.class.getDeclaredField("getTypes");
            getTypesField.setAccessible(true);

            setMethodsField = Reflector.class.getDeclaredField("setMethods");
            setMethodsField.setAccessible(true);

            setTypesField = Reflector.class.getDeclaredField("setTypes");
            setTypesField.setAccessible(true);

            mapField = Reflector.class.getDeclaredField("caseInsensitivePropertyMap");
            mapField.setAccessible(true);
        } catch (Exception e) {
            throw new MagicException(e);
        }
    }

    private Map<String, String> map = new HashMap<>();

    public MagicReflector(Class<?> clazz) {
        super(clazz);
        // 驼峰转化
        try {
            // get
            Map<String, Invoker> getMethods = (Map<String, Invoker>) getMethodsField.get(this);
            Map<String, Class<?>> getTypes = (Map<String, Class<?>>) getTypesField.get(this);

            Object[] array = getMethods.keySet().toArray();
            for (Object key : array) {
                String name = StrUtil.toUnderlineCase((String) key);
                if (!getMethods.containsKey(name)) {
                    getMethods.put(name, getMethods.get(key));
                    getTypes.put(name, getTypes.get(key));
                }
            }
        } catch (Exception e) {
            throw new MagicException(e);
        }

        try {
            // set
            Map<String, Invoker> setMethodsMap = (Map<String, Invoker>) setMethodsField.get(this);
            Map<String, Class<?>> setTypesMap = (Map<String, Class<?>>) setTypesField.get(this);

            Object[] array = setMethodsMap.keySet().toArray();
            for (Object key : array) {
                String name = StrUtil.toUnderlineCase((String) key);
                if (!setMethodsMap.containsKey(name)) {
                    setMethodsMap.put(name, setMethodsMap.get(key));
                    setTypesMap.put(name, setTypesMap.get(key));
                }
            }
        } catch (Exception e) {
            throw new MagicException(e);
        }

        try {
            // 下划线的大写转换
            map = (Map<String, String>) mapField.get(this);
            HashSet<String> set = new HashSet<>(map.keySet());

            for (Object key : set) {
                String value = map.get(key).toUpperCase(Locale.ENGLISH).replace("_", "");
                if (!map.containsKey(value)) {
                    map.put(value, map.get(key));
                }
            }
        } catch (Exception e) {
            throw new MagicException(e);
        }
    }

    /**
     * 重写查找属性，相当于设置了：configuration.setMapUnderscoreToCamelCase(true);
     *
     * @since 1.1.0
     */
    public String findPropertyName(String name) {
        if (name.contains("_")) {// 存在下划线
            name = name.replace("_", "");
        }
        return map.get(name.toUpperCase(Locale.ENGLISH));
    }
}
